from fs import *
import os, os.path

class LocalFile(FileOperations):
    def __init__(self, localfs, path):
        self.fs = localfs
        abspath = self.fs.abspath(path)
        localabs = self.fs.realpath(abspath)
        #if os.path.exists(localabs):
        #    raise OSError("File already exists.")
        if os.path.isdir(localabs):
            raise OSError("There exists a directory with the same path.")
        dname = os.path.dirname(localabs)
        if not os.path.exists(dname):
            raise OSError("Directory does not exist.")
        self.localpath = localabs
        self.fspath = abspath
        self.file = None
        
    def open(self, mode = ACCESS_RW):
        assert self.file == None
        rwmode = mode & ACCESS_RW
        #self.file = open(self.path, mode, buffering)
        modestr = {  ACCESS_READ : "rb",
                     ACCESS_WRITE : "rb+",
                     ACCESS_RW : "rb+",
                     }[rwmode]
        if not os.path.exists(self.localpath):
            modestr = "wb+"
        self.file = open(self.localpath, modestr, 0) # no buffering
        
    def seek(self, offset, whence = os.SEEK_SET):
        assert self.file != None
        self.file.seek(offset, os.SEEK_SET)
        
    def tell(self):
        assert self.file != None
        return self.file.tell()
        
    def read(self, size = -1):
        assert self.file != None
        return self.file.read(size)
    
    def write(self, buf, size = -1):
        assert self.file != None
        if size < 0:
            self.file.write(buf)
        else:
            self.file.write(buf[:size])
            
    def close(self):
        if self.file != None:
            self.file.close()
            self.file = None
            
    def path(self):
        return self.fspath



class LocalFileSystem(FileSystemOperations):
    def __init__(self, localpath):
        if not os.path.exists(localpath):
            raise OSError("Local path does not exist.")
        if not os.path.isdir(localpath):
            raise OSError("Local path is not a directory.")
        localabspath = os.path.abspath(localpath)
        # remove / or \ at the end of path, if any
        self.localpath = localabspath[-1] == os.path.sep and localabspath[:-1] or localabspath
        self.localsep = os.path.sep
        self.pwd = "" # root
        
    def realpath(self, abspath):
        return self.localpath + abspath.replace("/", self.localsep)
        
    def create(self, path):
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        if os.path.exists(localabs):
            raise OSError("File already exists.")
        return LocalFile(self, path)
    
    def open(self, path):
        lfile = LocalFile(self, path)
        lfile.open(ACCESS_RW)
        return lfile
    
    def exists(self, path):
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        return os.path.exists(localabs)
    
    def delete(self, path):
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        os.remove(localabs)
    
    def exists(self, path):
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        return os.path.exists(localabs)
    
    def setWorkingDirectory(self, newdir):
        newpath = self.abspath(newdir)
        self.pwd = newpath
    
    def isDirectory(self, path): # for directory structure file system
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        return os.path.isdir(localabs)
    ### private method
    def abspath(self, path):
        if path == None or path == "":
            raise ValueError("Path must not be null value.")
        pathsep = path.split("/")
        if pathsep[-1] == "":
            pathsep.pop()
        if '.' in pathsep:
            pathsep.remove('.')
        relatepath = self.pwd
        if len(pathsep) == 0 or pathsep[0] != "": # path is not already abs
            relateseps = relatepath.split('/')
            relateseps.extend(pathsep)
            pathsep = relateseps
        assert pathsep[0] == ''
        while ".." in pathsep:
            idx = pathsep.index("..")
            if idx <= 1:
                raise ValueError("Not a valid path given.")
            del pathsep[idx-1:idx+1]
        assert pathsep[0] == ''
        if len(pathsep) == 1:
            pathsep = ["", ""]
        return '/'.join(pathsep)
    
    def mkdir(self, path, permission = ACCESS_RWS):
        abspath = self.abspath(path)
        localabs = self.realpath(abspath)
        os.mkdir(localabs)
        
    def listpath(self, pathpattern):
        abspath = self.abspath(pathpattern)
        localabs = self.realpath(abspath)
        return os.listdir(localabs)